<?php
namespace heihei\filters\auth;
use yii;
use yii\filters\auth\AuthMethod;
use yii\base\Exception;
use yii\base\InvalidConfigException;
use yii\web\ForbiddenHttpException;
use yii\web\UnauthorizedHttpException;
use heihei\security\Jwt;

/**
 * JWT 登录
 *
 */
class JwtAuth extends AuthMethod
{
    /**
     * @var 传递的参数名称访问令牌
     */
    public $tokenParam = 'jwtToken';


    private $_jwt;
    
    /**
     * 设置jwt实例
     */
    public function setJwt($jwt){
        if(is_string($jwt)){
            $this->_jwt = Yii::$app->$jwt;
        }
        else{
            $this->_jwt = $jwt;
        }
        if($this->_jwt instanceof Jwt){
            return;
        }
        throw new InvalidConfigException("jwt配置错误");
    }

    /**
     * 还回设置jwt实例
     */
    public function getJwt(){
        if($this->_jwt == null){
            $this->_jwt = Yii::$app->securityJwt;
        }
        if($this->_jwt instanceof Jwt){
            return $this->_jwt;
        }
        throw new InvalidConfigException("jwt配置错误");
    }

    /**
     * @inheritdoc
     */
    public function authenticate($user, $request, $response)
    {
        $jwtToken = $this->getJwtToken();
        if(!is_string($jwtToken) || empty($jwtToken)){
            $user->logout();
            return null;
        }

        try{
            $jwtTokenInfo = $this->decode($jwtToken);  
        }
        catch(\UnexpectedValueException $e){
            throw new UnauthorizedHttpException($e->getMessage(), 403);
        }
        
        if(empty($jwtTokenInfo->uid)){
            throw new ForbiddenHttpException("未找JWT令牌里的登录信息！", 403);
        }

        $class = $user->identityClass;
        $identity = $class::findIdentity($jwtTokenInfo->uid);
        if ($identity && $user->login($identity)) {
            return $identity;
        }
        $this->handleFailure($response);       
        return null;     
    }

    /**
     * 获取请求的JWT Token
     */
    public function getJwtToken(){        
        if(isset($_COOKIE[$this->tokenParam]) && !empty($_COOKIE[$this->tokenParam])){
            return trim($_COOKIE[$this->tokenParam],'"');
        }
        $request = Yii::$app->getRequest();
        $jwtToken = $request->get($this->tokenParam);

        if(empty($jwtToken)){
            $jwtToken = $request->post($this->tokenParam);
        }

        if(empty($jwtToken)){
            $jwtToken = $request->getHeaders()->get($this->tokenParam);
        }
        $jwtToken = trim(urldecode($jwtToken),'"');
        return $jwtToken;
    }

    /**
     * JWT 解密
     *
     * @param object|array  $payload    token 可以是字符串 可以是数组
     *
     * @return 返回JWT 加密字符串
     */
    public function decode($jwtToken){
        return $this->getJwt()->decode($jwtToken);
    }

    /**
     * JWT 加密
     *
     * @param object|array  $payload    token 可以是字符串 可以是数组
     *
     * @return 返回JWT 加密字符串
     */
    public function encode($payload)
    {   
        return $this->getJwt()->encode($payload);
    }
}
